package com.ktjy.ch07.config;

import com.ktjy.ch07.config.handle.MyAuthenticationFailureHandler;
import com.ktjy.ch07.config.handle.MyAuthenticationSuccessHandler;
import com.ktjy.ch07.service.UserDetailsServiceImpl;
import jakarta.annotation.Resource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;

import javax.sql.DataSource;

import static org.springframework.security.config.Customizer.withDefaults;

@EnableWebSecurity
@Configuration
public class SecurityConfig {
    // PasswordEncoder pe = new BCryptPasswordEncoder();
//    @Bean
//    public PasswordEncoder getPw() {
//        return new BCryptPasswordEncoder();
//    }

    @Resource
    private UserDetailsServiceImpl userDetailsService;

    @Resource
    private DataSource dataSource; // 数据源对象


    @Bean
    public PersistentTokenRepository getPersistentTokenRepository() {
        JdbcTokenRepositoryImpl jdbcTokenRepository = new JdbcTokenRepositoryImpl();
        // 设置数据源对象
        jdbcTokenRepository.setDataSource(dataSource);
        // 设置保存[记住我]的用户信息的表，setCreateTableStartup(true)表示自动创建这张表
        // 需要注意的是：第一次启动的时候需要使用下面这行代码创建表，第二次启动之前，则要把这行代码注释掉
        //jdbcTokenRepository.setCreateTableOnStartup(true);
        return jdbcTokenRepository;
    }

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http)
            throws Exception {
        //表单提交
        http.formLogin(formLoginSpec -> formLoginSpec
                // 自定义登录页面(SpringSecurity 默认的登录页面就会不显示)
                .loginPage("/tologin")
                // 设置提交登录请求的路径，不配置请求就进入不到 doLogin 所对应方法中，
                // 其值要求和 login.html 登录页面中表单的 action 值保持一致
                .loginProcessingUrl("/doLogin")
                //.failureForwardUrl("/toError")
                // 配置登录成功后的跳转页面 (必须是 POST 请求)
                .successForwardUrl("/main")
                //.successHandler(new MyAuthenticationSuccessHandler("http://www.baidu.com"))
                .failureHandler(new MyAuthenticationFailureHandler("http://www.jd.com"))
                .permitAll());

        // 授权认证
        // 设置除了登录页面，其他所有请求都必须被登录认证后才能进行访问。
        http.authorizeHttpRequests((authz) -> authz
                // 设置/tologin 不需要被认证 premitAll 允许任何人都可以访问
                .requestMatchers("/tologin").permitAll()
                .requestMatchers("/css/**").permitAll()
                .requestMatchers("/toError").permitAll()
                .requestMatchers("/loLogin").permitAll()
                // anyRequest()为所有的请求， authenticated()表示登录认证后

                //main路径需要main的权限才能访问
                //.requestMatchers("/main").hasAuthority("main")
                // 即所有请求都必须被登录认证后才能进行访问
                .anyRequest().authenticated()
        ).httpBasic(withDefaults());

        // 记住我
        http.rememberMe((me) -> me
                .userDetailsService(userDetailsService)
                // 持久层对象
                .tokenRepository(getPersistentTokenRepository()));
        // 关闭 csrf 防火墙
        http.csrf(AbstractHttpConfigurer::disable);
        return http.build();
    }
}